import {Promise} from 'es6-promise';
import {Role} from "../core/defines";
import * as utils from "../core/utils";
import {BaseModel} from "../core/base.model";
import {Collection, ObjectID} from "mongodb";
import {
    FindParam,
    CountParam,
    FindOneParam,
    UpdateParam,
} from "../core/params";

export enum ProductLevel {
    EASY = 1, //简单
    MIDDLE = 2, //中等
    HARD = 3, //较难
}

export enum ProductStatus {
    CREATE = 1, //已创建
    STAGE = 2, //暂存
    PUBLISHED = 3, //已发布
    OFFLINE = 4, //下线
    REMOVED = 5, //已删除
}

export interface ProductMsg {
    id: ObjectID,
    nick_name: string,
    portrait?: string,
    content: string,
    time?: Date,
    code?: string,
}

export interface ProductInfo {
    _id?: ObjectID,
    code?: string,
    base?: {
        cate?: string,
        sub_cate?: string,
        video?: string,
        thumb?: string,
        name?: string,
        keyword?: string,
        describe?: string,
    },
    params?: {
        level?: ProductLevel,
        mins?: number,
        taste?: string,
    },
    procedure?: {
        title?: string,
        items?: Array<{
            title: string,
            image: string
        }>
    },
    mats?: {
        title?: string,
        items?: Array<{
            name: string,
            describe: string
        }>,
        detail?: Array<{
            name: string,
            image: string
        }>,
    }
    shop?: {
        id?: ObjectID,
        code?: string,
        name?: string,
        phone?: string,
        telephone?: string
        loc?: {prov: string, city: string, dist: string},
        address?: string,
    },
    trans?: {
        price: number,
        ship_free: boolean,
        start_num: number,
        free_amount: number,
        log?: string,
    },
    sales?: {
        iwom?: number,
        sales?: number
    },
    msgs?: Array<ProductMsg>,
    status?: ProductStatus,
    time?: Date
}

export interface SearchOpt {
    _id?: ObjectID,
    key?: string,
    cate?: string,
    sub_cate?: string,
    sort?: string,
    limit?: number,
    page?: number,
    match?: Object,
    status?: ProductStatus,
}

export enum ProductSearchType {
    ORDER_PREVIEW = 1,
}

export default class ProductModel extends BaseModel {

    constructor(coll: Collection) {
        super(coll);
    }

    name() {
        return 'ProductModel';
    }

    checkExist(filter: SearchOpt, params?: {role?: Role, type?: ProductSearchType}): Promise<any> {
        let role = params && params.role || null;
        switch (role) {
            default:
                filter.status = ProductStatus.PUBLISHED;
        }

        let project = {};
        let type = params && params.type || null;
        switch (type) {
            case ProductSearchType.ORDER_PREVIEW:
                project = {base: 1, trans: 1}; break;
            default:
                project = {};
        }
        return this.findOne(new FindOneParam(filter, project));
    }

    regroupByShop(products: Array<ProductInfo>) {
        let prodInfo = {};
        for (let prod of products) {
            let code = prod.shop.code;
            prodInfo[code] = prodInfo[code] || [];
            prodInfo[code].push(prod);
        }
        return prodInfo;
    }

    search(filter: SearchOpt): Promise<any> {
        let {key, cate, sub_cate, limit, sort, page} = filter;

        let match = {status: ProductStatus.PUBLISHED};
        if (cate) {
            match['base.cate'] = cate;
        }
        if (sub_cate) {
            match['base.sub_cate'] = sub_cate;
        }
        if (key) {
            let regKeys = new RegExp(key);
            match['$or'] = [
                {'base.name': regKeys},
                {'base.keyword': regKeys}
            ];
        }

        let count: number;
        return this.count(new CountParam(match)).then((totalCount) => {
            count = totalCount;

            let skip = page * limit || 0;
            let options = new FindParam(match, {
                time: 1,
                base: 1,
                trans: 1,
                sales: 1,
                params: 1,
                cookbook: 1,
            });
            options.sort = {time: -1};
            options.skip = skip;
            options.limit = limit;
            return this.find(options);
        }).then((records) => {
            let prods = [];
            records.forEach((e) => {
                prods.push({
                    thumb: e.base.thumb,
                    name: e.base.name,
                    special: e.base.special,
                    abstract: e.cookbook.abstract,
                    price: e.trans.price,
                    act_price: e.trans.act_price,
                    iwom: e.sales.iwom,
                    level: e.params.level,
                    mins: e.params.mins,
                    taste: e.params.taste
                });
            });
            return {
                records: prods || [],
                curr_page: page,
                total_count: count,
                total_page: Math.ceil(count / limit)
            };
        });
    }
}